package beartek.utils;

/**
 * @author Beartek
 * GNU AGPL v3
 * https://taksio.tk/beartek/agora
 */
import haxe.Serializer;
import haxe.Unserializer;
import haxe.net.WebSocket;
import haxe.net.WebSocketServer;
import haxe.io.Bytes;
import beartek.utils.Wtp_types;


class Wtps {
  public var n_clients(get,null) : Int;

  var server : WebSocketServer;
  var clients : Array<WebSocket> = new Array();

  public function new( bind_ip : String, port : Int, max_conn : Int = 100, ?secure_path : {CA: String, Certificate: String, Key: String}, debug : Bool = false ) {
    server = @:privateAccess new WebSocketServer(bind_ip, port, max_conn, secure_path, debug);

  }

  public function send_response( client_id : Int, type : String, data : Dynamic, conn_id : String = null ) : Void {
    clients[client_id].sendBytes(Bytes.ofString(Serializer.run({id: conn_id, type: type, data: data})));
  }

  public function refresh() : Void {
    var client = server.accept();
    if( client != null ) {
      var id : Int = clients.push(client) -1;
      client.onmessageBytes = function ( msg : Bytes ) {
        try {
          var data : {id: String, type: Pet_types, data: Dynamic} = Unserializer.run(msg.toString());

          this.on_pet(id, data);
        } catch(e:Dynamic) {
          this.on_client_error(id, 'Unserializer error: ' + Std.string(e));
        }
      }
      client.onerror = function ( msg : String ) {
        this.on_client_error(id, msg);
      }
      client.onopen = function() : Void {
        this.on_new_client(id);
      }
    }

    var to_remove : Array<WebSocket> = [];
    for (client in clients) {
      client.process();
      if (client.readyState == Closed) {
        to_remove.push(client);

        this.on_client_left(clients.indexOf(client));
      }
    }

    while (to_remove.length > 0) {
      clients.remove(to_remove.pop());
    }
  }

  public inline function get_n_clients() : Int {
    return clients.length;
  }

  public function close() : Void {
    for( client in clients ) {
      client.close();
      clients.remove(client);
      this.on_client_left(clients.indexOf(client));
    }
  }

  public dynamic function on_new_client( id : Int ) {
  }

  public dynamic function on_client_left( id : Int ) {
  }

  public dynamic function on_client_error( id: Int, msg : String ) {
  }

  public dynamic function on_pet( client_id : Int, pet : {id: String, type: Pet_types, data: Dynamic} ) {
  }

}
